package ui.swing.laf;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableModel;

import ui.swing.laf.MathcerDescriptor.FindResult;

public class RegexTestFrame extends JFrame {

	// -- InputPanel --
	private static final long serialVersionUID = 6451890048547090057L;

	private JPanel v_pnlLaf;

	private JComboBox v_cmbLaf;

	private JPanel v_pnlInput;

	private JLabel v_lblRegex;

	private JTextField v_txtRegex;

	private JLabel v_lblString;

	private JScrollPane v_sclPaneContent;

	private JTextArea v_taContent;

	private JButton v_btnFind;

	private JButton v_btnMatch;

	private JLabel v_lblMode;

	private JComboBox v_cmbMode;

	// -- ResultPanel --
	private JPanel v_pnlResult;

	private JScrollPane v_sclPaneResult;

	private JTable v_tblResult;

	private DefaultTableModel v_tbmResult;

	private JLabel v_lblStatus;

	// -- data --
	MathcerDescriptor md;

	public RegexTestFrame() {
		super("正则表达式测试");
		initUI();
		registerListener();
		getV_cmbLaf().setSelectedItem(UIManager.getSystemLookAndFeelClassName());
	}

	private void initUI() {
		getContentPane().add(getV_pnlLaf(), BorderLayout.NORTH);
		getContentPane().add(getV_pnlInput(), BorderLayout.CENTER);
		getContentPane().add(getV_pnlResult(), BorderLayout.SOUTH);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		pack();
		setVisible(true);
		setLocationRelativeTo(null);
	}

	private void registerListener() {
		getV_btnFind().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String regex = getV_txtRegex().getText();
				String testString = getV_taContent().getText();

				Pattern p;

				FlagOptionItem selItem = (FlagOptionItem) getV_cmbMode().getSelectedItem();
				int flagValue = selItem.getValue();
				if (flagValue != -1) {
					p = Pattern.compile(regex, flagValue);
				} else {
					p = Pattern.compile(regex);
				}
				md = new MathcerDescriptor(p.matcher(testString));

				showResultToTable();
			}
		});
		getV_btnMatch().addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String regex = getV_txtRegex().getText();
				String testString = getV_taContent().getText();

				Pattern p;

				FlagOptionItem selItem = (FlagOptionItem) getV_cmbMode().getSelectedItem();
				int flagValue = selItem.getValue();
				if (flagValue != -1) {
					p = Pattern.compile(regex, flagValue);
				} else {
					p = Pattern.compile(regex);
				}
				if (p.matcher(testString).matches()) {
					JOptionPane.showMessageDialog(RegexTestFrame.this, "匹配");
				} else {
					JOptionPane.showMessageDialog(RegexTestFrame.this, "不匹配");
				}
			}
		});
		getV_tblResult().getSelectionModel().addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
			}
		});
		getV_tblResult().addMouseListener(new MouseAdapter() {
			@Override
			public void mouseClicked(MouseEvent e) {
			}
		});
		getV_cmbLaf().addItemListener(new ItemListener() {
			public void itemStateChanged(ItemEvent e) {
				if (e.getStateChange() == ItemEvent.SELECTED) {
					String strLaf = (String) getV_cmbLaf().getSelectedItem();
					try {
						LookAndFeelUtils.changeLookAndFeel(strLaf, null, RegexTestFrame.this);
					} catch (Exception e1) {
						JOptionPane.showMessageDialog(RegexTestFrame.this, e.toString(), "Exception!", JOptionPane.ERROR_MESSAGE, null);
						e1.printStackTrace();
					}
				}
			}
		});
	}

	private void showResultToTable() {
		getV_lblStatus().setText("rs:" + md.getRegionStart() + " re:" + md.getRegionEnd() + " gc:" + md.getGroupCount());

		for (int i = 0, k = getV_tbmResult().getRowCount(); i < k; i++) {
			getV_tbmResult().removeRow(0);
		}

		for (int i = 0; i < md.getResultSize(); i++) {
			FindResult fr = md.getFindResult(i);
			for (int j = 0; j <= md.getGroupCount(); j++) {
				getV_tbmResult().addRow(new Object[] { fr.group(j), fr.start(j), fr.end(j), fr.hitEnd(j) });
			}
			getV_tbmResult().addRow(new Object[] { "", "", "", "" });
		}
	}

	private JPanel getV_pnlLaf() {
		if (v_pnlLaf == null) {
			v_pnlLaf = new JPanel(new BorderLayout());
			v_pnlLaf.add(getV_cmbLaf());
		}
		return v_pnlLaf;
	}

	private JComboBox getV_cmbLaf() {
		if (v_cmbLaf == null) {

			Vector<String> vec_laf = new Vector<String>();
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
				vec_laf.add(info.getClassName());
			}
			vec_laf.add("com.jtattoo.plaf.smart.SmartLookAndFeel");// haokan
			vec_laf.add("com.jtattoo.plaf.mcwin.McWinLookAndFeel");// 最好看
			vec_laf.add("com.jtattoo.plaf.luna.LunaLookAndFeel");// 很浅绿
			vec_laf.add("com.jtattoo.plaf.aluminium.AluminiumLookAndFeel");// 灰色
			vec_laf.add("com.jtattoo.plaf.bernstein.BernsteinLookAndFeel");// 太黄了
			vec_laf.add("com.jtattoo.plaf.hifi.HiFiLookAndFeel");// 全黑 不好看
			vec_laf.add("com.jtattoo.plaf.mint.MintLookAndFeel");
			vec_laf.add("com.jtattoo.plaf.aero.AeroLookAndFeel");
			vec_laf.add("com.jtattoo.plaf.fast.FastLookAndFeel");// buhk
			vec_laf.add("com.jtattoo.plaf.acryl.AcrylLookAndFeel");
			vec_laf.add("com.jtattoo.plaf.noire.NoireLookAndFeel");
			v_cmbLaf = new JComboBox(vec_laf);
		}
		return v_cmbLaf;
	}

	private JPanel getV_pnlInput() {
		if (v_pnlInput == null) {
			v_pnlInput = new JPanel(new GridBagLayout());
			v_pnlInput.setBorder(new TitledBorder("输入面板"));

			GridBagConstraints c = new GridBagConstraints();
			c.insets = new Insets(5, 5, 5, 5);

			c.anchor = GridBagConstraints.EAST;
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0.0;
			c.gridx = 1;
			c.gridy = 1;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_lblRegex(), c);

			c.anchor = GridBagConstraints.WEST;
			c.fill = GridBagConstraints.HORIZONTAL;
			c.weightx = 0.0;
			c.gridx = 2;
			c.gridy = 1;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_txtRegex(), c);

			c.anchor = GridBagConstraints.CENTER;
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0.0;
			c.gridx = 3;
			c.gridy = 1;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_btnFind(), c);

			c.anchor = GridBagConstraints.EAST;
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0.0;
			c.gridx = 1;
			c.gridy = 2;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_lblMode(), c);

			c.anchor = GridBagConstraints.WEST;
			c.fill = GridBagConstraints.HORIZONTAL;
			c.weightx = 0.0;
			c.gridx = 2;
			c.gridy = 2;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_cmbMode(), c);

			c.anchor = GridBagConstraints.CENTER;
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0.0;
			c.gridx = 3;
			c.gridy = 2;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_btnMatch(), c);

			c.anchor = GridBagConstraints.NORTHEAST;
			c.fill = GridBagConstraints.NONE;
			c.weightx = 0.0;
			c.gridx = 1;
			c.gridy = 3;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_lblString(), c);

			c.anchor = GridBagConstraints.CENTER;
			c.fill = GridBagConstraints.BOTH;
			c.weightx = 1.0;
			c.weighty = 1.0;
			c.gridx = 2;
			c.gridy = 3;
			c.gridwidth = 1;
			c.gridheight = 1;
			v_pnlInput.add(getV_sclPaneContent(), c);

		}
		return v_pnlInput;
	}

	private JPanel getV_pnlResult() {
		if (v_pnlResult == null) {
			v_pnlResult = new JPanel(new BorderLayout());
			v_pnlResult.setBorder(new TitledBorder("匹配结果"));
			v_pnlResult.add(getV_lblStatus(), BorderLayout.NORTH);
			v_pnlResult.add(getV_sclPaneResult(), BorderLayout.CENTER);
		}
		return v_pnlResult;
	}

	private JLabel getV_lblRegex() {
		if (v_lblRegex == null) {
			v_lblRegex = new JLabel("正则表达式");
			v_lblRegex.setPreferredSize(new Dimension(80, 20));
			v_lblRegex.setHorizontalAlignment(SwingConstants.RIGHT);
		}
		return v_lblRegex;
	}

	private JTextField getV_txtRegex() {
		if (v_txtRegex == null) {
			v_txtRegex = new JTextField();
			v_txtRegex.setPreferredSize(new Dimension(200, 20));
		}
		return v_txtRegex;
	}

	private JLabel getV_lblString() {
		if (v_lblString == null) {
			v_lblString = new JLabel("测试文字");
			v_lblString.setPreferredSize(new Dimension(80, 20));
			v_lblString.setHorizontalAlignment(SwingConstants.RIGHT);
		}
		return v_lblString;
	}

	private JScrollPane getV_sclPaneContent() {
		if (v_sclPaneContent == null) {
			v_sclPaneContent = new JScrollPane(getV_taContent());
			v_sclPaneContent.setPreferredSize(new Dimension(200, 100));
		}
		return v_sclPaneContent;
	}

	private JTextArea getV_taContent() {
		if (v_taContent == null) {
			v_taContent = new JTextArea();
		}
		return v_taContent;
	}

	private JScrollPane getV_sclPaneResult() {
		if (v_sclPaneResult == null) {
			v_sclPaneResult = new JScrollPane(getV_tblResult());
			v_sclPaneResult.setPreferredSize(new Dimension(0, 200));
		}
		return v_sclPaneResult;
	}

	private JTable getV_tblResult() {
		if (v_tblResult == null) {
			v_tblResult = new JTable(getV_tbmResult());
			v_tblResult.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		}
		return v_tblResult;
	}

	private DefaultTableModel getV_tbmResult() {
		if (v_tbmResult == null) {
			String[] columnNames = new String[] { "matched String", "start", "end", "hitEnd" };
			v_tbmResult = new DefaultTableModel(columnNames, 0);
		}
		return v_tbmResult;
	}

	private JButton getV_btnFind() {
		if (v_btnFind == null) {
			v_btnFind = new JButton("Find");
		}
		return v_btnFind;
	}

	private JButton getV_btnMatch() {
		if (v_btnMatch == null) {
			v_btnMatch = new JButton("Match");
		}
		return v_btnMatch;
	}

	private JComboBox getV_cmbMode() {
		if (v_cmbMode == null) {
			v_cmbMode = new JComboBox(new DefaultComboBoxModel(new FlagOptionItem[] { new FlagOptionItem("无", -1),
					new FlagOptionItem("多行模式(?m)", Pattern.MULTILINE), new FlagOptionItem("CANON_EQ", Pattern.CANON_EQ),
					new FlagOptionItem("大小写不敏感(?i)", Pattern.CASE_INSENSITIVE), new FlagOptionItem("COMMENTS", Pattern.COMMENTS),
					new FlagOptionItem("DOTALL(?s)", Pattern.DOTALL), new FlagOptionItem("UNICODE_CASE", Pattern.UNICODE_CASE),
					new FlagOptionItem("UNIX_LINES(?d)", Pattern.UNIX_LINES), }));
			v_cmbMode.setPreferredSize(new Dimension(200, 20));
		}
		return v_cmbMode;
	}

	private JLabel getV_lblMode() {
		if (v_lblMode == null) {
			v_lblMode = new JLabel("匹配模式");
			v_lblMode.setPreferredSize(new Dimension(80, 20));
			v_lblMode.setHorizontalAlignment(SwingConstants.RIGHT);
		}
		return v_lblMode;
	}

	private JLabel getV_lblStatus() {
		if (v_lblStatus == null) {
			v_lblStatus = new JLabel(" ");
		}
		return v_lblStatus;
	}

	private static class FlagOptionItem {
		private String text;
		private int value;

		public FlagOptionItem(String text, int value) {
			this.text = text;
			this.value = value;
		}

		public int getValue() {
			return value;
		}

		public String toString() {
			return text;
		}

	}

	public static void main(String[] args) {
		new RegexTestFrame();
	}

}

class MathcerDescriptor {
	int groupCount;
	int regionStart;
	int regionEnd;
	List<FindResult> listResult = new ArrayList<FindResult>();

	public MathcerDescriptor(Matcher matcher) {
		this.groupCount = matcher.groupCount();
		this.regionStart = matcher.regionStart();
		this.regionEnd = matcher.regionEnd();
		while (matcher.find()) {
			FindResult findResult = new FindResult();
			int loop = matcher.groupCount();
			for (int i = 0; i <= loop; i++) {
				findResult.addGroup(matcher.group(i));
				findResult.addStart(matcher.start(i));
				findResult.addEnd(matcher.end(i));
				findResult.addHitEnd(matcher.hitEnd());
			}
			listResult.add(findResult);
		}
	}

	public FindResult getFindResult(int index) {
		return listResult.get(index);
	}

	public int getGroupCount() {
		return groupCount;
	}

	public int getResultSize() {
		return listResult.size();
	}

	public static class FindResult {

		private List<String> lst_group = new ArrayList<String>();
		private List<Integer> lst_start = new ArrayList<Integer>();
		private List<Integer> lst_end = new ArrayList<Integer>();
		private List<Boolean> lst_hitEnd = new ArrayList<Boolean>();

		public String group(int index) {
			return lst_group.get(index);
		}

		public int start(int index) {
			return lst_start.get(index);
		}

		public int end(int index) {
			return lst_end.get(index);
		}

		public Boolean hitEnd(int index) {
			return lst_hitEnd.get(index);
		}

		private void addGroup(String group) {
			lst_group.add(group);
		}

		private void addStart(Integer start) {
			lst_start.add(start);
		}

		private void addEnd(Integer end) {
			lst_end.add(end);
		}

		private void addHitEnd(Boolean hitEnd) {
			lst_hitEnd.add(hitEnd);
		}
	}

	public int getRegionStart() {
		return regionStart;
	}

	public int getRegionEnd() {
		return regionEnd;
	}
}
